home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The AGA Experience 3
/
AGA Experience Volume 3 (1997)(NFA - SAdENESS)[!].iso
/
software
/
utilities
/
graphics
/
raylab
/
source
/
intersct.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-01
|
38KB
|
1,451 lines
/*
name: intersct.c
Intersection-routines
---------------------
These routines will calculate the t-parameter of a line,
which corresponds to the point where the given line intersects with
the given primitive. The routines return zero (0) if no intersection
occured.
This source-code is part of the RayLab 1.1 package, and it is provided
for your compiling pleasure. You may use it, change it, re-compile it
etc., as long as nobody else but you receive the changes/compilations
that you have made!
You may not use any part(s) of this source-code for your own productions
without the permission from the author of RayLab. Please read the legal
information found in the users documentation for RayLab for more details.
*/
#include "defs.h"
#include "extern.h"
/**********************************************************************
*
* Try all objects for intersection, and return object number
* and intersection information.
*
**********************************************************************/
long Intersect_All_Objects(INTERSECTION *Intersct, LINE *RayLine)
{
INTERSECTION TmpIntersct;
double t, tnew;
long i, ObjNum;
ObjNum=-1L;
t=-1.0;
for(i=0;i<NumObjects;i++) {
tnew=Intersect_Object(&TmpIntersct, RayLine, ObjectArray[i]);
if((tnew>EPSILON)&&((tnew<t)||(t<=EPSILON))) {
ObjNum=i;
t=tnew;
*Intersct=TmpIntersct;
}
}
return(ObjNum);
}
/**********************************************************************
*
* Get (possible) intersection with a given object
*
**********************************************************************/
double Intersect_Object(INTERSECTION *Intrsct, LINE *Line, OBJECT *Object)
{
LINE TransformedLine;
register double t,a,b,c;
register long i;
VECTOR tempv;
if(CheckForBounding(Line, Object)==TRUE) { /* Check for boundings, if any */
TransformedLine.Origin=Line->Origin;
TransformedLine.Direction=Line->Direction;
if(Object->Transform.NumTransforms>0) {
for(i=Object->Transform.NumTransforms-1L;i>=0L;i--) {
switch(Object->Transform.Entry[i].Type) {
case TRANSFORM_SCALE:
tempv=Object->Transform.Entry[i].Values;
a=1.0/tempv.x; b=1.0/tempv.y; c=1.0/tempv.z;
TransformedLine.Origin.x*=a; TransformedLine.Origin.y*=b; TransformedLine.Origin.z*=c;
TransformedLine.Direction.x*=a; TransformedLine.Direction.y*=b; TransformedLine.Direction.z*=c;
break;
case TRANSFORM_MOVE:
SubVector((VECTOR *)&TransformedLine.Origin,(VECTOR *)&TransformedLine.Origin,&Object->Transform.Entry[i].Values);
break;
case TRANSFORM_ROTATE:
NegVector(&tempv,&Object->Transform.Entry[i].Values);
RevRotatePoint(&TransformedLine.Origin,&tempv);
RevRotateVector(&TransformedLine.Direction,&tempv);
break;
case TRANSFORM_NONE:
default:
break;
}
}
}
switch(Object->ShapeType) {
case SHAPE_PLANE:
t=Intersect_Plane(Intrsct, &TransformedLine, Object);
break;
case SHAPE_SPHERE:
t=Intersect_Sphere(Intrsct, &TransformedLine, Object);
break;
case SHAPE_ELLIPSOID:
t=Intersect_Ellipsoid(Intrsct, &TransformedLine, Object);
break;
case SHAPE_TRIANGLE:
t=Intersect_Triangle(Intrsct, &TransformedLine, Object);
break;
case SHAPE_TRIANGLELIST:
t=Intersect_TriangleList(Intrsct, &TransformedLine, Object);
break;
case SHAPE_BOX:
t=Intersect_Box(Intrsct, &TransformedLine, Object);
break;
case SHAPE_DISC:
t=Intersect_Disc(Intrsct, &TransformedLine, Object);
break;
case SHAPE_CYLINDER:
t=Intersect_Cylinder(Intrsct, &TransformedLine, Object);
break;
case SHAPE_CONE:
t=Intersect_Cone(Intrsct, &TransformedLine, Object);
break;
case SHAPE_TORUS:
t=Intersect_Torus(Intrsct, &TransformedLine, Object);
break;
case SHAPE_PEAK:
t=Intersect_Peak(Intrsct, &TransformedLine, Object);
break;
case SHAPE_DEOFLASKA:
t=Intersect_Deoflaska(Intrsct, &TransformedLine, Object);
break;
case SHAPE_CSG:
t=Intersect_CSG(Intrsct, &TransformedLine, Object);
break;
default:
t=0.0;
break;
}
if(t>EPSILON) {
if(Object->Transform.NumTransforms>0) { /* Transform intersection to its real place/orientation in space */
for(i=0L;i<Object->Transform.NumTransforms;i++) {
tempv=Object->Transform.Entry[i].Values;
switch(Object->Transform.Entry[i].Type) {
case TRANSFORM_SCALE:
a=tempv.x; b=tempv.y; c=tempv.z;
Intrsct->IPoint.x*=a; Intrsct->IPoint.y*=b; Intrsct->IPoint.z*=c;
Intrsct->Normal.x*=1.0/a; Intrsct->Normal.y*=1.0/b; Intrsct->Normal.z*=1.0/c;
break;
case TRANSFORM_MOVE:
Intrsct->IPoint.x+=tempv.x;
Intrsct->IPoint.y+=tempv.y;
Intrsct->IPoint.z+=tempv.z;
break;
case TRANSFORM_ROTATE:
RotatePoint(&Intrsct->IPoint,&tempv);
RotateVector(&Intrsct->Normal,&tempv);
break;
case TRANSFORM_NONE:
default:
break;
}
}
}
if(Object->Invert==INVERT_TRUE) {
NegVector(&Intrsct->Normal,&Intrsct->Normal); /* "Reverse" surface */
}
}
}
return(t);
}
/**********************************************************************
*
* These are the actual intersection calculation routines
*
**********************************************************************/
double Intersect_Plane(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
{
register double t,pnx,pny,pnz,a,tmp;
double lvx,lvy,lvz,lx0,ly0,lz0;
PLANE *Plane;
PlaneIntersectionAttempts++;
Plane=(PLANE *)Obj->Shape;
lvx=Line->Direction.x; lvy=Line->Direction.y; lvz=Line->Direction.z;
lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
pnx=Plane->Normal.x; pny=Plane->Normal.y; pnz=Plane->Normal.z; a=Plane->a;
tmp=pnx*lvx+pny*lvy+pnz*lvz;
if(tmp!=0.0) {
t=-(pnx*lx0+pny*ly0+pnz*lz0-a)/tmp;
if(t>EPSILON) {
PlaneIntersections++;
Intrsct->IPoint.x=lx0+lvx*t; Intrsct->IPoint.y=ly0+lvy*t; Intrsct->IPoint.z=lz0+lvz*t;
Intrsct->Normal.x=pnx; Intrsct->Normal.y=pny; Intrsct->Normal.z=pnz;
Intrsct->Texture=&Obj->Texture;
Intrsct->Shadow=Obj->Shadow;
}
else t=0.0;
}
else t=0.0;
return(t);
}
double Intersect_Sphere(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
{
double vx,vy,vz,lx0,ly0,lz0,sx0,sy0,sz0,r;
register double s,sroot,vxdx,vydy,vzdz,vxsqr,vysqr,vzsqr;
double t;
double dx,dy,dz;
double dxsqr,dysqr,dzsqr;
double vsum,t1,t2;
SPHERE *Sphere;
SphereIntersectionAttempts++;
Sphere=(SPHERE *)Obj->Shape;
vx=Line->Direction.x; vy=Line->Direction.y; vz=Line->Direction.z;
lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
sx0=Sphere->Centre.x; sy0=Sphere->Centre.y; sz0=Sphere->Centre.z;
r=Sphere->r;
/* These are used more than once, */
dx=lx0-sx0; dy=ly0-sy0; dz=lz0-sz0; /* thus much time is saved by not */
vxdx=vx*dx; vydy=vy*dy; vzdz=vz*dz; /* performing the same operation */
dxsqr=dx*dx; dysqr=dy*dy; dzsqr=dz*dz; /* twice (or even more). */
vxsqr=vx*vx; vysqr=vy*vy; vzsqr=vz*vz;
vsum=(vxsqr+vysqr+vzsqr);
sroot=2*(vxdx*(vydy+vzdz)+vydy*vzdz)+r*r*vsum;
sroot-=vxsqr*(dysqr+dzsqr)+vysqr*(dxsqr+dzsqr)+vzsqr*(dxsqr+dysqr);
t=0.0;
if(sroot>=0) {
sroot=sqrt(sroot);
s=-(vxdx+vydy+vzdz);
t1=(s+sroot)/vsum; /* Note: vsum!=0, always */
t2=(s-sroot)/vsum; /* Also: t2<=t1, as sroot>=0 */
if(t2>EPSILON) t=t2;
else if(t1>EPSILON) t=t1;
if(t>EPSILON) {
SphereIntersections++;
Intrsct->IPoint.x=lx0+vx*t; Intrsct->IPoint.y=ly0+vy*t; Intrsct->IPoint.z=lz0+vz*t;
Intrsct->Normal.x=Intrsct->IPoint.x-sx0;
Intrsct->Normal.y=Intrsct->IPoint.y-sy0;
Intrsct->Normal.z=Intrsct->IPoint.z-sz0;
Intrsct->Texture=&Obj->Texture;
Intrsct->Shadow=Obj->Shadow;
}
}
return(t);
}
double Intersect_Ellipsoid(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
{
double vx,vy,vz,lx0,ly0,lz0,ex0,ey0,ez0,a,b,c;
register double sroot,asqr,bsqr,csqr,vxdx,vydy,vzdz;
double t;
double dx,dy,dz;
double vxsqr,vysqr,vzsqr,dxsqr,dysqr,dzsqr;
double r,s,t1,t2;
ELLIPSOID *Ellipsoid;
EllipsoidIntersectionAttempts++;
Ellipsoid=(ELLIPSOID *)Obj->Shape;
vx=Line->Direction.x; vy=Line->Direction.y; vz=Line->Direction.z;
lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
ex0=Ellipsoid->Centre.x; ey0=Ellipsoid->Centre.y; ez0=Ellipsoid->Centre.z;
a=Ellipsoid->Radius.x; b=Ellipsoid->Radius.y; c=Ellipsoid->Radius.z;
asqr=a*a; bsqr=b*b; csqr=c*c; /* These are used more than once, */
dx=lx0-ex0; dy=ly0-ey0; dz=lz0-ez0; /* thus much time is saved by not */
vxdx=vx*dx; vydy=vy*dy; vzdz=vz*dz; /* performing the same operation */
dxsqr=dx*dx; dysqr=dy*dy; dzsqr=dz*dz; /* twice (or even more). */
vxsqr=vx*vx; vysqr=vy*vy; vzsqr=vz*vz;
s=-((vxdx/asqr)+(vydy/bsqr)+(vzdz/csqr));
sroot=csqr*(vxsqr*bsqr+vysqr*asqr)+vzsqr*asqr*bsqr;
sroot+=2*(vxdx*(csqr*vydy+bsqr*vzdz)+asqr*vydy*vzdz);
sroot-=vxsqr*(csqr*dysqr+bsqr*dzsqr);
sroot-=vysqr*(csqr*dxsqr+asqr*dzsqr);
sroot-=vzsqr*(bsqr*dxsqr+asqr*dysqr);
t=0.0;
if(sroot>=0) {
sroot=sqrt(sroot)/(a*b*c);
r=((vxsqr/asqr)+(vysqr/bsqr)+(vzsqr/csqr));
t1=(s+sroot)/r;
t2=(s-sroot)/r;
if((t1>EPSILON)&&((t1<t2)||(t2<EPSILON))) {
t=t1;
EllipsoidIntersections++;
}
else if((t2>EPSILON)&&((t2<t1)||(t1<EPSILON))) {
t=t2;
EllipsoidIntersections++;
}
if(t>EPSILON) {
Intrsct->IPoint.x=lx0+vx*t; Intrsct->IPoint.y=ly0+vy*t; Intrsct->IPoint.z=lz0+vz*t;
Intrsct->Normal.x=(Intrsct->IPoint.x-ex0)/(a*a);
Intrsct->Normal.y=(Intrsct->IPoint.y-ey0)/(b*b);
Intrsct->Normal.z=(Intrsct->IPoint.z-ez0)/(c*c);
Intrsct->Texture=&Obj->Texture;
Intrsct->Shadow=Obj->Shadow;
}
}
return(t);
}
double Intersect_Triangle(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
{
double t,ttmp,pnx,pny,pnz;
double lvx,lvy,lvz,lx0,ly0,lz0;
double ui,vi,u[4],v[4];
register double un,vn,um,vm;
short sign,count,n,m;
TRIANGLE *Triangle;
TriangleIntersectionAttempts++;
Triangle=(TRIANGLE *)Obj->Shape;
lvx=Line->Direction.x; lvy=Line->Direction.y; lvz=Line->Direction.z;
lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
pnx=Triangle->Normal.x; pny=Triangle->Normal.y; pnz=Triangle->Normal.z;
t=0.0;
ttmp=pnx*lvx+pny*lvy+pnz*lvz;
if(ttmp!=0.0) {
ttmp=-(pnx*lx0+pny*ly0+pnz*lz0-Triangle->Offset)/ttmp;
if(ttmp>EPSILON) {
switch(Triangle->Projection) { /* Transform to 2D coordinates */
case PROJ_YZ:
ui=ly0+ttmp*lvy;
vi=lz0+ttmp*lvz;
break;
case PROJ_XZ:
ui=lx0+ttmp*lvx;
vi=lz0+ttmp*lvz;
break;
case PROJ_XY:
ui=lx0+ttmp*lvx;
vi=ly0+ttmp*lvy;
break;
}
u[0]=Triangle->Corners[0].u-ui;
u[1]=Triangle->Corners[1].u-ui;
u[2]=Triangle->Corners[2].u-ui;
v[0]=Triangle->Corners[0].v-vi;
v[1]=Triangle->Corners[1].v-vi;
v[2]=Triangle->Corners[2].v-vi;
u[3]=u[0]; v[3]=v[0];
count=0; /* Determine amount of sides crossed */
for(n=0;n<3;n++) {
m=n+1;
vn=v[n]; vm=v[m];
if(vn>=0.0) sign=1; else sign=-1;
if(vm>=0.0) sign+=1; else sign-=1;
if(sign==0) {
un=u[n]; um=u[m];
if((un>=0.0)&&(um>=0.0)) count+=1;
else if((un>=0.0)||(um>=0.0)) {
if((um-vm*(um-un)/(vm-vn))>0.0) count+=1;
}
}
}
if((count&0x01)==1) { /* If odd amount of sides were crossed... */
TriangleIntersections++;
t=ttmp;
Intrsct->Normal.x=pnx;
Intrsct->Normal.y=pny;
Intrsct->Normal.z=pnz;
Intrsct->IPoint.x=lx0+lvx*t;
Intrsct->IPoint.y=ly0+lvy*t;
Intrsct->IPoint.z=lz0+lvz*t;
Intrsct->Texture=&Obj->Texture;
Intrsct->Shadow=Obj->Shadow;
}
}
}
return(t);
}
double Intersect_TriangleList(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
{
double t,ttmp,pnx,pny,pnz;
double lvx,lvy,lvz,lx0,ly0,lz0;
double ui,vi,u[4],v[4];
register double un,vn,um,vm;
short sign,count,n,m;
TRIANGLELIST *Triangle;
Triangle=(TRIANGLELIST *)Obj->Shape;
lvx=Line->Direction.x; lvy=Line->Direction.y; lvz=Line->Direction.z;
lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
t=0.0;
while(Triangle!=NULL) {
TriangleIntersectionAttempts++;
pnx=Triangle->Normal.x; pny=Triangle->Normal.y; pnz=Triangle->Normal.z;
ttmp=pnx*lvx+pny*lvy+pnz*lvz;
if(ttmp!=0.0) {
ttmp=-(pnx*lx0+pny*ly0+pnz*lz0-Triangle->Offset)/ttmp;
if(ttmp>EPSILON) {
switch(Triangle->Projection) { /* Transform to 2D coordinates */
case PROJ_YZ:
ui=ly0+ttmp*lvy;
vi=lz0+ttmp*lvz;
break;
case PROJ_XZ:
ui=lx0+ttmp*lvx;
vi=lz0+ttmp*lvz;
break;
case PROJ_XY:
ui=lx0+ttmp*lvx;
vi=ly0+ttmp*lvy;
break;
}
u[0]=Triangle->Corners[0].u-ui;
u[1]=Triangle->Corners[1].u-ui;
u[2]=Triangle->Corners[2].u-ui;
v[0]=Triangle->Corners[0].v-vi;
v[1]=Triangle->Corners[1].v-vi;
v[2]=Triangle->Corners[2].v-vi;
u[3]=u[0]; v[3]=v[0];
count=0; /* Determine amount of sides crossed */
for(n=0;n<3;n++) {
m=n+1;
vn=v[n]; vm=v[m];
if(vn>=0.0) sign=1; else sign=-1;
if(vm>=0.0) sign+=1; else sign-=1;
if(sign==0) {
un=u[n]; um=u[m];
if((un>=0.0)&&(um>=0.0)) count+=1;
else if((un>=0.0)||(um>=0.0)) {
if((um-vm*(um-un)/(vm-vn))>0.0) count+=1;
}
}
}
}
if((count&0x01)==1) { /* If odd amount of sides were crossed... */
if((ttmp>EPSILON)&&((t<EPSILON)||(ttmp<t))) {
TriangleIntersections++;
t=ttmp;
Intrsct->Normal.x=pnx;
Intrsct->Normal.y=pny;
Intrsct->Normal.z=pnz;
Intrsct->IPoint.x=lx0+lvx*t;
Intrsct->IPoint.y=ly0+lvy*t;
Intrsct->IPoint.z=lz0+lvz*t;
}
}
}
Triangle=Triangle->NextTriangle;
}
if(t>EPSILON) {
Intrsct->Texture=&Obj->Texture;
Intrsct->Shadow=Obj->Shadow;
}
return(t);
}
double Intersect_Box(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
{
register double t,told,ttmp;
double lvx,lvy,lvz,lx0,ly0,lz0;
register double ipx,ipy,ipz;
POINT ip;
VECTOR norm;
BOX *Box;
BoxIntersectionAttempts++;
Box=(BOX *)Obj->Shape;
told=-1.0;
lvx=Line->Direction.x; lvy=Line->Direction.y; lvz=Line->Direction.z;
lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
if(lvz!=0.0) {
ttmp=(Box->Corners[0].z-lz0)/lvz; /* xy-plane, z-min */
if(ttmp>EPSILON) {
ipx=lx0+lvx*ttmp; ipy=ly0+lvy*ttmp;
if((ipx>=Box->Corners[0].x)&&(ipx<=Box->Corners[1].x)&&(ipy>=Box->Corners[0].y)&&(ipy<=Box->Corners[1].y)) {
told=ttmp; ip.x=ipx; ip.y=ipy; ip.z=Box->Corners[0].z; norm.x=norm.y=0.0; norm.z=-1.0;
}
}
ttmp=(Box->Corners[1].z-lz0)/lvz; /* xy-plane, z-max */
if((ttmp>EPSILON)&&((told<0.0)||(ttmp<told))) {
ipx=lx0+lvx*ttmp; ipy=ly0+lvy*ttmp;
if((ipx>=Box->Corners[0].x)&&(ipx<=Box->Corners[1].x)&&(ipy>=Box->Corners[0].y)&&(ipy<=Box->Corners[1].y)) {
told=ttmp; ip.x=ipx; ip.y=ipy; ip.z=Box->Corners[1].z; norm.x=norm.y=0.0; norm.z=1.0;
}
}
}
if(lvy!=0.0) {
ttmp=(Box->Corners[0].y-ly0)/lvy; /* xz-plane, y-min */
if((ttmp>EPSILON)&&((told<0.0)||(ttmp<told))) {
ipx=lx0+lvx*ttmp; ipz=lz0+lvz*ttmp;
if((ipx>=Box->Corners[0].x)&&(ipx<=Box->Corners[1].x)&&(ipz>=Box->Corners[0].z)&&(ipz<=Box->Corners[1].z)) {
told=ttmp; ip.x=ipx; ip.z=ipz; ip.y=Box->Corners[0].y; norm.x=norm.z=0.0; norm.y=-1.0;
}
}
ttmp=(Box->Corners[1].y-ly0)/lvy; /* xz-plane, y-max */
if((ttmp>EPSILON)&&((told<0.0)||(ttmp<told))) {
ipx=lx0+lvx*ttmp; ipz=lz0+lvz*ttmp;
if((ipx>=Box->Corners[0].x)&&(ipx<=Box->Corners[1].x)&&(ipz>=Box->Corners[0].z)&&(ipz<=Box->Corners[1].z)) {
told=ttmp; ip.x=ipx; ip.z=ipz; ip.y=Box->Corners[1].y; norm.x=norm.z=0.0; norm.y=1.0;
}
}
}
if(lvy!=0.0) {
ttmp=(Box->Corners[0].x-lx0)/lvx; /* yz-plane, x-min */
if((ttmp>EPSILON)&&((told<0.0)||(ttmp<told))) {
ipy=ly0+lvy*ttmp; ipz=lz0+lvz*ttmp;
if((ipy>=Box->Corners[0].y)&&(ipy<=Box->Corners[1].y)&&(ipz>=Box->Corners[0].z)&&(ipz<=Box->Corners[1].z)) {
told=ttmp; ip.y=ipy; ip.z=ipz; ip.x=Box->Corners[0].x; norm.y=norm.z=0.0; norm.x=-1.0;
}
}
ttmp=(Box->Corners[1].x-lx0)/lvx; /* yz-plane, x-max */
if((ttmp>EPSILON)&&((told<0.0)||(ttmp<told))) {
ipy=ly0+lvy*ttmp; ipz=lz0+lvz*ttmp;
if((ipy>=Box->Corners[0].y)&&(ipy<=Box->Corners[1].y)&&(ipz>=Box->Corners[0].z)&&(ipz<=Box->Corners[1].z)) {
told=ttmp; ip.y=ipy; ip.z=ipz; ip.x=Box->Corners[1].x; norm.y=norm.z=0.0; norm.x=1.0;
}
}
}
if(told>EPSILON) {
t=told;
BoxIntersections++;
Intrsct->IPoint=ip;
Intrsct->Normal=norm;
Intrsct->Texture=&Obj->Texture;
Intrsct->Shadow=Obj->Shadow;
}
else t=0.0;
return(t);
}
double Intersect_Disc(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
{
register double t;
DiscIntersectionAttempts++;
t=Intersect_DiscShape(Intrsct, Line, (DISC *)Obj->Shape);
if(t>EPSILON) {
Intrsct->Texture=&Obj->Texture;
Intrsct->Shadow=Obj->Shadow;
}
return(t);
}
double Intersect_DiscShape(INTERSECTION *Intrsct, LINE *Line, DISC *Disc)
{
register double t,pnx,pny,pnz,a,tmp;
double lvx,lvy,lvz,lx0,ly0,lz0,dx,dy,dz;
POINT ip;
lvx=Line->Direction.x; lvy=Line->Direction.y; lvz=Line->Direction.z;
lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
pnx=Disc->Plane.Normal.x; pny=Disc->Plane.Normal.y; pnz=Disc->Plane.Normal.z; a=Disc->Plane.a;
t=0.0;
tmp=pnx*lvx+pny*lvy+pnz*lvz;
if(tmp!=0.0) {
tmp=-(pnx*lx0+pny*ly0+pnz*lz0-a)/tmp;
if(tmp>EPSILON) {
ip.x=lx0+lvx*tmp; ip.y=ly0+lvy*tmp; ip.z=lz0+lvz*tmp;
dx=ip.x-Disc->Centre.x;
dy=ip.y-Disc->Centre.y;
dz=ip.z-Disc->Centre.z;
if((dx*dx+dy*dy+dz*dz)<(Disc->r*Disc->r)) {
t=tmp;
DiscIntersections++;
Intrsct->IPoint=ip;
Intrsct->Normal.x=pnx; Intrsct->Normal.y=pny; Intrsct->Normal.z=pnz;
}
}
}
return(t);
}
double Intersect_Cylinder(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
{
register double lvx,lvy,l0x,l0y,lvx2plvy2;
double rsqr,a,b,c,t,t1,t2,z1,z2;
int sidehit;
CYLINDER *Cylinder;
CylinderIntersectionAttempts++;
Cylinder=(CYLINDER *)Obj->Shape;
lvx=Line->Direction.x; lvy=Line->Direction.y;
l0x=Line->Origin.x; l0y=Line->Origin.y;
rsqr=Cylinder->r; rsqr*=rsqr;
lvx2plvy2=1.0/(lvx*lvx+lvy*lvy);
a=(rsqr-l0x*l0x-l0y*l0y)*lvx2plvy2;
b=(lvx*l0x+lvy*l0y)*lvx2plvy2;
c=a+b*b;
t=0.0;
if(c>=0.0) {
c=sqrt(c);
t1=-b-c; /* t1 <= t2 */
t2=-b+c;
z1=z2=Line->Origin.z;
z1+=Line->Direction.z*t1;
z2+=Line->Direction.z*t2;
a=Cylinder->h; /* a = height of cylinder */
sidehit=FALSE;
if(t1>EPSILON) {
if((z1>=0.0)&&(z1<=a)) {
t=t1;
Intrsct->IPoint.z=z1;
sidehit=TRUE;
}
}
else if(t2>EPSILON) {
if((z2>=0.0)&&(z2<=a)) {
t=t2;
Intrsct->IPoint.z=z2;
sidehit=TRUE;
}
}
b=Line->Origin.z; c=1.0/Line->Direction.z;
t1=(0.0-b)*c; /* t1 <=> bottom hit */
t2=(a-b)*c; /* t2 <=> top hit */
if(t1>EPSILON) {
b=l0x+lvx*t1; c=l0y+lvy*t1;
if((b*b+c*c)>rsqr) t1=0.0; /* Outside of the cyliunder? */
}
if(t2>EPSILON) {
if((t1>EPSILON)&&(t1<t2)) t2=0.0;
else {
b=l0x+lvx*t2; c=l0y+lvy*t2;
if((b*b+c*c)>rsqr) t2=0.0;
else t1=0.0;
}
}
if((t1>EPSILON)&&((t1<t)||(t<EPSILON))) {
t=t1;
CreatePoint(&Intrsct->IPoint,l0x+lvx*t1,l0y+lvy*t1,0.0);
CreateVector(&Intrsct->Normal,0.0,0.0,-1.0);
sidehit=FALSE;
}
else if((t2>EPSILON)&&((t2<t)||(t<EPSILON))) {
t=t2;
CreatePoint(&Intrsct->IPoint,b,c,a);
CreateVector(&Intrsct->Normal,0.0,0.0,1.0);
sidehit=FALSE;
}
if(sidehit==TRUE) {
Intrsct->Normal.x=Intrsct->IPoint.x=l0x+lvx*t;
Intrsct->Normal.y=Intrsct->IPoint.y=l0y+lvy*t;
Intrsct->Normal.z=0.0;
}
if(t>=EPSILON) {
CylinderIntersections++;
Intrsct->Texture=&Obj->Texture;
Intrsct->Shadow=Obj->Shadow;
}
}
return(t);
}
double Intersect_Cone(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
{
double lvx,lvy,lvz,l0x,l0y,l0z;
double r1,r2,h,A,B,C,a,b,c,t,t1,t2,x,y,z;
int sidehit;
CONE *Cone;
ConeIntersectionAttempts++;
Cone=(CONE *)Obj->Shape;
t = 0.0;
r1 = Cone->r1; r2 = Cone->r2; h = Cone->h;
lvx = Line->Direction.x; lvy = Line->Direction.y; lvz = Line->Direction.z;
l0x = Line->Origin.x; l0y = Line->Origin.y; l0z = Line->Origin.z;
c = (r2-r1)/h;
A = (lvx*lvx + lvy*lvy - c*c*lvz*lvz);
if(A!=0.0) {
A = 1.0 / A;
B = lvx*l0x + lvy*l0y - lvz*c*(l0z*c + r1);
C = l0x*l0x + l0y*l0y - l0z*c*(l0z*c + 2.0*r1) - r1*r1;
a = A*B;
b = a*a - A*C;
if(b>=0) {
b = sqrt(b); /* b > 0 */
t1 = -a - b; /* t1 < t2 */
t2 = -a + b;
sidehit = FALSE;
/* Intersection with sides */
if(t2 > EPSILON) {
z = l0z + t2*lvz;
if((z>0.0)&&(z<h)) {
t = t2; sidehit = TRUE;
}
if(t1 > EPSILON) {
z = l0z + t1*lvz;
if((z>0.0)&&(z<h)) {
t = t1; sidehit = TRUE;
}
}
}
/* Intersection with top/bottom */
if(lvz!=0.0) {
t1 = -l0z/lvz; t2 = (h-l0z)/lvz;
if((t1>EPSILON)&&((t<EPSILON)||(t1<t))) {
x = l0x+lvx*t1; y = l0y+lvy*t1;
if((x*x + y*y) <= (r1*r1)) {
t = t1; sidehit = FALSE;
Intrsct->IPoint.x = x; Intrsct->IPoint.y = y;
Intrsct->Normal.x = Intrsct->Normal.y = 0.0;
Intrsct->Normal.z = -1.0;
}
}
if((t2>EPSILON)&&((t<EPSILON)||(t2<t))) {
x = l0x+lvx*t2; y = l0y+lvy*t2;
if((x*x + y*y) <= (r2*r2)) {
t = t2; sidehit = FALSE;
Intrsct->IPoint.x = x; Intrsct->IPoint.y = y;
Intrsct->Normal.x = Intrsct->Normal.y = 0.0;
Intrsct->Normal.z = 1.0;
}
}
}
if(t>EPSILON) {
ConeIntersections++;
Intrsct->IPoint.z = l0z+lvz*t;
if(sidehit == TRUE) {
x = Intrsct->IPoint.x = Intrsct->Normal.x = l0x+lvx*t;
y = Intrsct->IPoint.y = Intrsct->Normal.y = l0y+lvy*t;
Intrsct->Normal.z = -sqrt(x*x + y*y)*c;
}
Intrsct->Texture = &Obj->Texture;
Intrsct->Shadow = Obj->Shadow;
}
}
}
return(t);
}
double Torus_Function(double t, double r0, double r1, LINE *Line)
{
register double a,b,c,f;
a=Line->Origin.x+Line->Direction.x*t;
b=Line->Origin.y+Line->Direction.y*t;
c=Line->Origin.z+Line->Direction.z*t;
f = sqrt(a*a + b*b) - r0;
f = f*f + c*c - r1*r1;
return(f);
}
double Torus_Derivata(double t, double r0, LINE *Line)
{
register double a,b,c,df;
a=Line->Origin.x+Line->Direction.x*t;
b=Line->Origin.y+Line->Direction.y*t;
c=Line->Origin.z+Line->Direction.z*t;
df = (1.0 - r0/sqrt(a*a + b*b))*(a + b);
df *= (Line->Direction.x + Line->Direction.y);
df += c*Line->Direction.z;
df += df;
return(df);
}
double Intersect_Torus(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
{
register double r0,r1,tn,fn,tb,fb,diff;
double tnp1,fnp1;
double dx,dy,dz,x0,y0,z0;
double cylr,tcyl1o,tcyl2o,tcyl1i,tcyl2i,tpln1,tpln2,z1,z2,pr1,pr2;
double dx2pdy2,a,b,c,ts[6],t;
int i,tamount,sortchange,FoundHit;
TORUS *Torus;
TorusIntersectionAttempts++;
Torus=(TORUS *)Obj->Shape;
dx=Line->Direction.x; dy=Line->Direction.y; dz=Line->Direction.z;
x0=Line->Origin.x; y0=Line->Origin.y; z0=Line->Origin.z;
r0=Torus->r0; r1=Torus->r1;
dx2pdy2=1.0/(dx*dx+dy*dy);
cylr=(r0+r1); /* Check for outer cylinder-bounding */
a=(cylr*cylr-x0*x0-y0*y0)*dx2pdy2;
b=(dx*x0+dy*y0)*dx2pdy2;
c=a+b*b;
t=0.0;
if(c>=0.0) { /* If found cylinder, try the rest */
c=sqrt(c);
tcyl1o=-b-c; /* tcyl1o < tcyl2o */
tcyl2o=-b+c;
if(tcyl2o>EPSILON) { /* Don't do anything if BOTH hits behind */
z1=(z0+dz*tcyl1o);
z2=(z0+dz*tcyl2o);
if(!(((z1>r1)&&(z2>r1))||((z1<-r1)&&(z2<-r1)))) {
if(fabs(z1)>r1) tcyl1o=0.0;
if(fabs(z2)>r1) tcyl2o=0.0;
cylr=(r0-r1); /* Check for inner cylinder */
a=(cylr*cylr-x0*x0-y0*y0)*dx2pdy2;
b=(dx*x0+dy*y0)*dx2pdy2;
c=a+b*b;
if(c>=0.0) {
c=sqrt(c);
tcyl1i=-b-c; /* tcyl1i < tcyl2i */
tcyl2i=-b+c;
z1=(z0+dz*tcyl1i);
z2=(z0+dz*tcyl2i);
if(fabs(z1)>r1) tcyl1i=0.0;
if(fabs(z2)>r1) tcyl2i=0.0;
}
else {
tcyl1i=tcyl2i=0.0;
}
tpln1=(r1-z0)/dz; /* Check for plane intersection */
tpln2=(-r1-z0)/dz;
a=x0+dx*tpln1; b=y0+dy*tpln1; pr1=sqrt(a*a+b*b);
a=x0+dx*tpln2; b=y0+dy*tpln2; pr2=sqrt(a*a+b*b);
if((pr1>(r0+r1))||(pr1<(r0-r1))) tpln1=0.0;
if((pr2>(r0+r1))||(pr2<(r0-r1))) tpln2=0.0;
if( (tcyl1o>EPSILON)||(tcyl2o>EPSILON)||
(tcyl1i>EPSILON)||(tcyl2i>EPSILON)||
(tpln1>EPSILON)||(tpln2>EPSILON) ) {
tamount=0;
if(fabs(tcyl1o)>EPSILON) ts[tamount++]=tcyl1o;
if(fabs(tcyl2o)>EPSILON) ts[tamount++]=tcyl2o;
if(fabs(tcyl1i)>EPSILON) ts[tamount++]=tcyl1i;
if(fabs(tcyl2i)>EPSILON) ts[tamount++]=tcyl2i;
if(fabs(tpln1)>EPSILON) ts[tamount++]=tpln1;
if(fabs(tpln2)>EPSILON) ts[tamount++]=tpln2;
if(((tamount&1)!=0)||(tamount>4)) {
tamount=-1;
}
else {
sortchange=1;
while(sortchange>0) { /* Sort bound-hits */
sortchange=0; /* (closest last) */
for(i=0;i<tamount-1;i++) {
if(ts[i+1]>ts[i]) {
a=ts[i]; ts[i]=ts[i+1]; ts[i+1]=a;
sortchange++;
}
}
}
a=ts[1];
if(tamount>2) {
b=ts[2]; c=ts[3];
}
ts[1]=(ts[0]+a)*0.5; ts[2]=a;
tamount++;
if(tamount>3) {
ts[3]=b; ts[4]=(b+c)*0.5; ts[5]=c;
tamount++;
}
}
FoundHit=FALSE;
while((tamount>=2)&&(FoundHit==FALSE)) {
tb=ts[tamount-2]; /* tb is further away than... */
tn=ts[tamount-1]; /* ...tn */
fb=Torus_Function(tb,r0,r1,Line);
fn=Torus_Function(tn,r0,r1,Line);
if(((fn<0.0)&&(fb>0.0))||((fn>0.0)&&(fb<0.0))) {
if((tb>EPSILON)||(tn>EPSILON)) {
i=0; diff=1.0; /* Trapets-method */
while((diff>NUMEPSILON)&&(i<10)) {
tnp1=tn-fn*(tb-tn)/(fb-fn);
diff=fabs(tnp1-tn);
if(diff>NUMEPSILON) {
fnp1=Torus_Function(tnp1,r0,r1,Line);
if(((fnp1<0.0)&&(fb<0.0))||((fnp1>0.0)&&(fb>0.0))) {
fb=fn; tb=tn; /* Switch direction */
}
fn=fnp1;
i++;
}
tn=tnp1;
}
if(tn>NUMEPSILON) {
FoundHit=TRUE;
}
}
}
else { /* Newton-Raphson */
if((tamount==2)||(tamount==5)) {
tn=tb; fn=fb;
}
i=0; diff=1.0;
while((diff>NUMEPSILON)&&(i<6)) {
diff=fn/Torus_Derivata(tn,r0,Line);
tn-=diff;
diff=fabs(diff);
if(diff>NUMEPSILON) {
fn=Torus_Function(tn,r0,r1,Line);
i++;
}
}
if((diff<=NUMEPSILON)&&(tn>NUMEPSILON)) {
FoundHit=TRUE;
}
}
if(FoundHit==FALSE) {
tamount--;
if(tamount==4) tamount--;
}
}
if(FoundHit==TRUE) {
TorusIntersections++;
t=tn;
Intrsct->Texture=&Obj->Texture;
Intrsct->Shadow=Obj->Shadow;
Intrsct->IPoint.x=x0+dx*t;
Intrsct->IPoint.y=y0+dy*t;
Intrsct->IPoint.z=z0+dz*t;
a=Intrsct->IPoint.x; b=Intrsct->IPoint.y;
c=1.0-r0/sqrt(a*a+b*b);
Intrsct->Normal.x=a*c;
Intrsct->Normal.y=b*c;
Intrsct->Normal.z=Intrsct->IPoint.z;
}
}
}
}
}
return(t);
}
double Peak_Function(double t, LINE *Line)
{
register double x,y,z,f;
x = Line->Origin.x + Line->Direction.x*t;
y = Line->Origin.y + Line->Direction.y*t;
z = Line->Origin.z + Line->Direction.z*t;
f = x*x + y*y;
if(z>0.0) f -= 1.0/(z*z);
else f += 1.0/(z*z);
return( f );
}
double Peak_Derivata(double t, LINE *Line)
{
register double x,y,z,f;
x = Line->Origin.x + Line->Direction.x*t;
y = Line->Origin.y + Line->Direction.y*t;
z = Line->Origin.z + Line->Direction.z*t;
f = x*Line->Direction.x + y*Line->Direction.y;
if(z>0.0) f += Line->Direction.z/(z*z*z);
else f -= Line->Direction.z/(z*z*z);
return( 2.0*f );
}
double Intersect_Peak(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
{
double lvx,lvy,lvz,lx0,ly0,lz0;
double t,t_a,t_b,f1,f2,tnp1,fnp1,fprim;
register double A,B,C,D,a,b;
int i;
PeakIntersectionAttempts++;
lvx = Line->Direction.x; lvy = Line->Direction.y; lvz = Line->Direction.z;
lx0 = Line->Origin.x; ly0 = Line->Origin.y; lz0 = Line->Origin.z;
a = 1.0/lvx; b = 1.0/lvy;
t_a = -(ly0*a+lx0*b)/(lvy*a+lvx*b); /* Closest point to z-axis */
t_b = -lz0/lvz; /* Intersection with z=0 */
/* Use Newton-Raphson to find hit with "floor" */
tnp1 = t_b; b = 1.0; i=0;
tnp1 = 0.0;
while((fabs(b)>NUMEPSILON)&&((i++)<6)) {
b = Peak_Function(tnp1,Line) / Peak_Derivata(tnp1,Line);
tnp1 -= b;
}
t_b = tnp1; /* t_b = intersection with "floor" */
/* a = t_a;
f1 = D + C*a;
a *= t_a; f1 += B*a;
a *= t_a; f1 += A*a; */ /* f1 = f(t_a) */
/* if(f1>0.0) !utanför! */
t = t_b;
if(t>(NUMEPSILON*4.0)) {
PeakIntersections++;
a = lx0 + lvx*t; b = ly0 + lvy*t;
Intrsct->IPoint.x=a; Intrsct->Normal.x=a;
Intrsct->IPoint.y=b; Intrsct->Normal.y=b;
a = lz0 + lvz*t;
Intrsct->IPoint.z=a; Intrsct->Normal.y=1.0/(a*a*a);
NormalizeVector(&Intrsct->Normal,&Intrsct->Normal); /* Can be _HUGE_ and _SMALL_! */
Intrsct->Texture = &Obj->Texture;
Intrsct->Shadow = Obj->Shadow;
}
else t = 0.0;
return(t);
}
double Intersect_Deoflaska(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
{
register double t,r0,dr,h,tn,tnp1,t1,t2,diff;
double dx,dy,dz,x0,y0,z0,unitdz;
double tcyl1,tcyl2,cylr,dx2pdy2,a,b,c,z1,z2;
int i, MultiplePeriods, LastCheck, FoundHit;
DEOFLASKA *Deo;
DeoflaskaIntersectionAttempts++;
Deo=(DEOFLASKA *)Obj->Shape;
dx=Line->Direction.x; dy=Line->Direction.y; dz=Line->Direction.z;
x0=Line->Origin.x; y0=Line->Origin.y; z0=Line->Origin.z;
r0=Deo->r0; dr=Deo->dr; h=Deo->h;
cylr=(r0+dr)*1.03; /* Check for cylinder-bounding */
dx2pdy2=1.0/(dx*dx+dy*dy);
a=(cylr*cylr-x0*x0-y0*y0)*dx2pdy2;
b=(dx*x0+dy*y0)*dx2pdy2;
c=a+b*b;
if(c>=0.0) { /* If found cylinder, try numerical root-finding */
c=sqrt(c);
tcyl1=-b-c; /* tcyl1 < tcyl2 */
tcyl2=-b+c;
if(tcyl2>EPSILON) { /* Don't do anything if BOTH hits behind */
FoundHit=FALSE;
LastCheck=FALSE;
if(((dz*dz)/(dx*dx+dy*dy))>0.25) MultiplePeriods=TRUE;
else MultiplePeriods=FALSE;
t1=t2=tcyl1;
unitdz=fabs(dz)/sqrt(dx*dx+dy*dy+dz*dz);
while((FoundHit==FALSE)&&(LastCheck==FALSE)) {
t1=t2; /* Determine interval t1 <= t <= t2 containing max one root */
if(MultiplePeriods==TRUE) {
z1=(z0+dz*t1);
if(dz>0.0) {
z2=(floor((z1+PID2)/PI)*PI)+PID2;
/* z2=floor((z1+PI)/PI)*PI; */
if((z2-z1)<EPSILON) z2+=PI;
} else {
z2=(floor((z1-PID2)/PI)*PI)+PID2;
/* z2=floor(z1/PI)*PI; */
if((z1-z2)<EPSILON) z2-=PI;
}
t2=(z2-z0)/dz;
if(t2>=tcyl2) {
t2=tcyl2;
LastCheck=TRUE;
}
tn=(t1+t2)*0.5; /* Start in the middle of the interval */
}
else {
if(t2<=(tcyl1+NUMEPSILON)) {
t1=tcyl1;
t2=(tcyl1+tcyl2)*0.5;
tn=tcyl1;
}
else {
t1=(tcyl1+tcyl2)*0.5;
t2=tcyl2;
tn=tcyl2;
LastCheck=TRUE;
}
}
if(t2>EPSILON) {
i=0; diff=1.0;
while((diff>NUMEPSILON)&&(i<6)) {
a=(x0+dx*tn); b=(y0+dy*tn); c=(r0-dr*sin(z0+dz*tn));
diff=(a*a+b*b-c*c)/(2*a*dx+2*b*dy+2*c*dr*cos(z0+dz*tn)*dz);
tnp1=tn-diff;
diff=fabs(diff);
tn=tnp1;
i++;
}
if((diff<NUMEPSILON)&&(tn>(4.0*NUMEPSILON))&&(tn>=t1)&&(tn<=t2)) FoundHit=TRUE;
else FoundHit=FALSE;
}
}
if((FoundHit==TRUE)&&(tn>(4.0*NUMEPSILON))&&(tn>=tcyl1)&&(tn<=tcyl2)) {
DeoflaskaIntersections++;
t=tn;
Intrsct->Texture=&Obj->Texture;
Intrsct->Shadow=Obj->Shadow;
Intrsct->IPoint.x=Intrsct->Normal.x=x0+dx*t;
Intrsct->IPoint.y=Intrsct->Normal.y=y0+dy*t;
Intrsct->IPoint.z=z0+dz*t;
Intrsct->Normal.z=(r0-dr*sin(Intrsct->IPoint.z))*dr*cos(Intrsct->IPoint.z);
}
else t=0.0;
}
else t=0.0;
}
else t=0.0;
return(t);
}
double Intersect_CSG(INTERSECTION *Intrsct, LINE *Line, OBJECT *Obj)
{
register double t, t1, t2, ttmp;
short operator, inside1, inside2, leftobj;
INTERSECTION Intersct1, Intersct2;
LINE NewLine;
CSG *CsgObject;
CsgIntersectionAttempts++;
CsgObject=(CSG *)Obj->Shape;
t=0.0; operator=CsgObject->Operator;
switch(operator) {
/* --- Logical AND (also used for MINUS) --- */
case CSG_OP_AND:
t=t1=t2=0.0;
inside1=inside2=CSG_OUTSIDE;
leftobj=FALSE;
NewLine.Direction=Line->Direction;
NewLine.Origin=Line->Origin;
while((leftobj==FALSE)&&(inside1==CSG_OUTSIDE)) {
ttmp=Intersect_Object(&Intersct1,&NewLine,CsgObject->Object1);
if(ttmp>EPSILON) {
t1+=ttmp;
inside1=InsideObject(CsgObject->Object2,&Intersct1.IPoint);
NewLine.Origin=Intersct1.IPoint;
}
else leftobj=TRUE;
}
leftobj=FALSE;
NewLine.Origin=Line->Origin;
while((leftobj==FALSE)&&(inside2==CSG_OUTSIDE)) {
ttmp=Intersect_Object(&Intersct2,&NewLine,CsgObject->Object2);
if(ttmp>EPSILON) {
t2+=ttmp;
inside2=InsideObject(CsgObject->Object1,&Intersct2.IPoint);
NewLine.Origin=Intersct2.IPoint;
}
else leftobj=TRUE;
}
if((inside1==CSG_INSIDE)&&(inside2==CSG_OUTSIDE)) {
t=t1;
CopyIntersection(Intrsct,&Intersct1);
}
else if((inside1==CSG_OUTSIDE)&&(inside2==CSG_INSIDE)) {
t=t2;
CopyIntersection(Intrsct,&Intersct2);
}
else if((inside1==CSG_INSIDE)&&(inside2==CSG_INSIDE)) {
if(t1<t2) {
t=t1;
CopyIntersection(Intrsct,&Intersct1);
} else {
t=t2;
CopyIntersection(Intrsct,&Intersct2);
}
}
break;
/* --- Logical OR (single surface) --- */
case CSG_OP_OR:
t=t1=t2=0.0;
inside1=inside2=CSG_INSIDE;
leftobj=FALSE;
NewLine.Direction=Line->Direction;
NewLine.Origin=Line->Origin;
while((leftobj==FALSE)&&(inside1==CSG_INSIDE)) {
ttmp=Intersect_Object(&Intersct1,&NewLine,CsgObject->Object1);
if(ttmp>EPSILON) {
t1+=ttmp;
inside1=InsideObject(CsgObject->Object2,&Intersct1.IPoint);
NewLine.Origin=Intersct1.IPoint;
}
else leftobj=TRUE;
}
leftobj=FALSE;
NewLine.Origin=Line->Origin;
while((leftobj==FALSE)&&(inside2==CSG_INSIDE)) {
ttmp=Intersect_Object(&Intersct2,&NewLine,CsgObject->Object2);
if(ttmp>EPSILON) {
t2+=ttmp;
inside2=InsideObject(CsgObject->Object1,&Intersct2.IPoint);
NewLine.Origin=Intersct2.IPoint;
}
else leftobj=TRUE;
}
if((inside1==CSG_OUTSIDE)&&(inside2==CSG_INSIDE)) {
t=t1;
CopyIntersection(Intrsct,&Intersct1);
}
else if((inside1==CSG_INSIDE)&&(inside2==CSG_OUTSIDE)) {
t=t2;
CopyIntersection(Intrsct,&Intersct2);
}
else if((inside1==CSG_OUTSIDE)&&(inside2==CSG_OUTSIDE)) {
if(t1<t2) {
t=t1;
CopyIntersection(Intrsct,&Intersct1);
} else {
t=t2;
CopyIntersection(Intrsct,&Intersct2);
}
}
break;
/* --- PLUS (closest hit, simple OR) --- */
case CSG_OP_PLUS:
t1=Intersect_Object(&Intersct1,Line,CsgObject->Object1);
t2=Intersect_Object(&Intersct2,Line,CsgObject->Object2);
if(t1>EPSILON) {
if(t1<t2) t=t1;
else if(t2>EPSILON) t=t2;
else t=t1;
}
else if(t2>EPSILON) t=t2;
if(t>EPSILON) {
if(fabs(t-t1)<EPSILON) CopyIntersection(Intrsct,&Intersct1);
else CopyIntersection(Intrsct,&Intersct2);
}
break;
default:
break;
}
if(t>0) CsgIntersections++;
return(t);
}
/**********************************************************************
*
* Test for bounding intersections
*
**********************************************************************/
int CheckForBounding(LINE *Line, OBJECT *Obj)
{
switch(Obj->BoundType) {
case BOUND_BOX:
return(CheckForBoundingBox(Line,(BOX *)Obj->Bound));
break;
case BOUND_SPHERE:
return(CheckForBoundingSphere(Line,(SPHERE *)Obj->Bound));
break;
case BOUND_NONE:
default:
return(TRUE);
break;
}
}
int CheckForBoundingBox(LINE *Line, BOX *Box)
{
register double ttmp;
double lvx,lvy,lvz,lx0,ly0,lz0;
register double ipx,ipy,ipz;
lvx=Line->Direction.x; lvy=Line->Direction.y; lvz=Line->Direction.z;
lx0=Line->Origin.x; ly0=Line->Origin.y; lz0=Line->Origin.z;
if(lvz!=0.0) {
ttmp=(Box->Corners[0].z-lz0)/lvz; /* xy-plane, z-min */
if(ttmp>EPSILON) {
ipx=lx0+lvx*ttmp; ipy=ly0+lvy*ttmp;
if((ipx>=Box->Corners[0].x)&&(ipx<=Box->Corners[1].x)&&(ipy>=Box->Corners[0].y)&&(ipy<=Box->Corners[1].y))
return(TRUE);
}
ttmp=(Box->Corners[1].z-lz0)/lvz; /* xy-plane, z-max */
if(ttmp>EPSILON) {
ipx=lx0+lvx*ttmp; ipy=ly0+lvy*ttmp;
if((ipx>=Box->Corners[0].x)&&(ipx<=Box->Corners[1].x)&&(ipy>=Box->Corners[0].y)&&(ipy<=Box->Corners[1].y))
return(TRUE);
}
}
if(lvy!=0.0) {
ttmp=(Box->Corners[0].y-ly0)/lvy; /* xz-plane, y-min */
if(ttmp>EPSILON) {
ipx=lx0+lvx*ttmp; ipz=lz0+lvz*ttmp;
if((ipx>=Box->Corners[0].x)&&(ipx<=Box->Corners[1].x)&&(ipz>=Box->Corners[0].z)&&(ipz<=Box->Corners[1].z))
return(TRUE);
}
ttmp=(Box->Corners[1].y-ly0)/lvy; /* xz-plane, y-max */
if(ttmp>EPSILON) {
ipx=lx0+lvx*ttmp; ipz=lz0+lvz*ttmp;
if((ipx>=Box->Corners[0].x)&&(ipx<=Box->Corners[1].x)&&(ipz>=Box->Corners[0].z)&&(ipz<=Box->Corners[1].z))
return(TRUE);
}
}
if(lvx!=0.0) {
ttmp=(Box->Corners[0].x-lx0)/lvx; /* yz-plane, x-min */
if(ttmp>EPSILON) {
ipy=ly0+lvy*ttmp; ipz=lz0+lvz*ttmp;
if((ipy>=Box->Corners[0].y)&&(ipy<=Box->Corners[1].y)&&(ipz>=Box->Corners[0].z)&&(ipz<=Box->Corners[1].z))
return(TRUE);
}
ttmp=(Box->Corners[1].x-lx0)/lvx; /* yz-plane, x-max */
if(ttmp>EPSILON) {
ipy=ly0+lvy*ttmp; ipz=lz0+lvz*ttmp;
if((ipy>=Box->Corners[0].y)&&(ipy<=Box->Corners[1].y)&&(ipz>=Box->Corners[0].z)&&(ipz<=Box->Corners[1].z))
return(TRUE);
}
}
return(FALSE);
}
int CheckForBoundingSphere(LINE *Line, SPHERE *Sphere)
{
double vx,vy,vz,r;
register double sroot,vydy,vzdz,vxsqr,vysqr,vzsqr;
double dx,dy,dz;
double dxsqr,dysqr,dzsqr;
vx=Line->Direction.x; vy=Line->Direction.y; vz=Line->Direction.z;
r=Sphere->r;
dx=Line->Origin.x-Sphere->Centre.x;
dy=Line->Origin.y-Sphere->Centre.y;
dz=Line->Origin.z-Sphere->Centre.z;
vydy=vy*dy; vzdz=vz*dz;
dxsqr=dx*dx; dysqr=dy*dy; dzsqr=dz*dz;
vxsqr=vx*vx; vysqr=vy*vy; vzsqr=vz*vz;
sroot=2*(vx*dx*(vydy+vzdz)+vydy*vzdz)+r*r*(vxsqr+vysqr+vzsqr);
sroot-=vxsqr*(dysqr+dzsqr)+vysqr*(dxsqr+dzsqr)+vzsqr*(dxsqr+dysqr);
if(sroot>=0.0) return(TRUE);
else return(FALSE);
}
/* Misc. */
void CopyIntersection(INTERSECTION *i1, INTERSECTION *i2)
{
i1->IPoint=i2->IPoint;
i1->Normal=i2->Normal;
i1->Texture=i2->Texture;
i1->Shadow=i2->Shadow;
}